package com.enjoyor.soa.traffic.ping.efoms.dubbo;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.geotools.data.shapefile.index.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import com.enjoyor.soa.traffic.ping.efoms.pojo.PingResultPojo;
import com.enjoyor.soa.traffic.util.helper.TimeHelper;

/**
 *
 * 对IPPool内的所有的ip进行ping，获取结果
 * 通过监听机制，将结果放入事件体中
 * @ClassNameIPPingDevService
 * @Description TODO
 * @Author ZSY
 * @Date 2019/3/1 9:41
 * @Version 1.0
 **/
@Component
public class IPPingDevService {
    
    @Value("${ping.result.file.isSave}")
    private Boolean pingFileIsSave;
    
    @Value("${ping.result.file.dir}")
    private String pingFileDir;
    
    @Value("${ping.server.system}")
    private String pingSystem;
    
    @Autowired
    private IPCategoryService ipCategoryService;

    @Autowired
    private ParsePingResultListener pingResultListener;

    @Autowired
    private TaskExecutor taskExecutor;

    /**
     * 定时对相关设备进行ping，获取结果，
     */
    @Scheduled(cron="0 */${ping.task.period} * * * ?")
    public void pingDevScheduled()throws Exception{
        Map<String,PingResultPojo> map = ipCategoryService.getIPMapPool();
        if(pingFileIsSave) {
        	try { 
            	File writeName = new File(pingFileDir); // 相对路径，如果没有则要建立一个新的output.txt文件 
    	    	writeName.createNewFile(); // 创建新文件,有同名的文件的话直接覆盖 
    	    	FileOutputStream fos = null;
    	    	if(!writeName.exists()){ 
    	    		writeName.createNewFile();//如果文件不存在，就创建该文件 
    	    		fos = new FileOutputStream(writeName);//首次写入获取 
    	    	}else{ 
    	    		//如果文件已存在，那么就在文件末尾追加写入 
    	    		fos = new FileOutputStream(writeName,true);//这里构造方法多了一个参数true,表示在文件末尾追加写入 
    	    	}
    	    	OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");//指定以UTF-8格式写入文件
    	    	String startT = "start**********************" + TimeHelper.dateToLongString() + "设备总数：" + map.size();
    	    	osw.write(startT+"\r\n"); // \r\n即为换行 
        		osw.close(); // 写入完成关闭流
    	    } catch (IOException e) { 
    	    	e.printStackTrace(); 
    	    }
        }
        System.out.println("start**********************" + TimeHelper.dateToLongString() + "设备总数：" + map.size());
        for (Map.Entry<String,PingResultPojo> entry : map.entrySet()) {
            //多线程异步执行ping
            final Map.Entry<String,PingResultPojo> ndoe = entry;
            taskExecutor.execute(() -> {
            	PingResultPojo pingResultPojo = ndoe.getValue();
                pingDevSendResult(pingResultPojo);
            });
        }
    }


    /**
     * ping设备信息，并调用监听命令
     * @param ipAddress
     * @param times
     */
    public void pingDevSendResult(PingResultPojo pingResultPojo) {
    	PingResultPojo resultPojo = new PingResultPojo();
    	String devStatus = pingResultPojo.getDevStatus();
    	String ipAddress = pingResultPojo.getIP();
    	if(null == ipAddress || "".equals(ipAddress)) {
    		return;
    	}
    	Date date = new Date();
    	resultPojo = ping(pingResultPojo);
    	Date date2 = new Date();
    	//System.out.println("========="+(date2.getTime()-date.getTime()));
    	/*if(EnumDicPublic.DEVICE_STATUS_USE.getKey().equals(devStatus)) {
    		resultPojo = ping(pingResultPojo);
    	}else {
    		resultPojo = pingResultPojo;
    	}*/
        //发布监听事件
        pingResultListener.sendResult(resultPojo);

    }

    /**
     * 调用CMD命令ping设备IP
     *
     * @param ipAddress
     * @return
     */
    public PingResultPojo ping(PingResultPojo pingResultPojo) {
        //PingResultPojo pingResultPojo = new PingResultPojo(ipAddress,times,timeout);
    	String ipAddress = pingResultPojo.getIP();
    	if(null == ipAddress || "".equals(ipAddress)) {
    		return null;
    	}
    	int times = pingResultPojo.getTimes();
    	int timeout = pingResultPojo.getTimeout();
        BufferedReader in = null;
        Runtime r = Runtime.getRuntime(); // 将要执行的ping命令,此命令是windows格式的命令
        
        String pingCommand = "ping " + ipAddress + " -n " + times + " -w " + timeout;
        if("linux".equals(pingSystem)) {
        	pingCommand = "ping -c " + times + " " + ipAddress;
        	//System.out.println("\n pingCommand"+pingCommand);
        }
        try {
            Process p = r.exec(pingCommand); // 在指定的环形下执行指定的命令。这里的意思是在windows下执行cmd的ping命令；
            if (p == null) {
                return null;
            }
            in = new BufferedReader(new InputStreamReader(p.getInputStream(), "GBK")); // 逐行检查输出,计算类似出现=23ms
            // TTL=62字样的次数
            int connectedCount = 0; // 设置链接次数；
            String line = null;
            List listMessage = new ArrayList<>();
            while ((line = in.readLine()) != null) { // in.readLine()读取字符流中的字符；并传入下面的方法进行校验；
            	if("linux".equals(pingSystem)) {
                    connectedCount = getCheckResultLinux(line);
            	}else {
                    connectedCount = getCheckResultWindows(line);
            	}
                if (!line.equals("") && connectedCount == 1) {
                    listMessage.add(line);
                }
            } // 如果出现类似=23ms TTL=62这样的字样,出现的次数=测试次数则返回真
            pingResultPojo.setPingResult(listMessage);
            //System.out.println(pingResultPojo.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            try {
                in.close(); // 关闭流；
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return pingResultPojo;
    }

 // 若line含有=18ms TTL=16字样,说明已经ping通,返回1,否則返回0.
    private int getCheckResultWindows(String line) { // 
    	//System.out.println("控制台输出的结果为:"+line);
        Pattern pattern = Pattern.compile("(\\d+ms)(\\s+)(TTL=\\d+)", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(line); // 正则表达式；寻找对应字符的数据流；
        //循环判断正则表达式中是否包含以上的规则数据；
        while (matcher.find()) {
            return 1;
        }
        return 0;
    }
    
    // 若line含有=18ms TTL=16字样,说明已经ping通,返回1,否則返回0.
    private int getCheckResultLinux(String line) { // 
    	//System.out.println("控制台输出的结果为:"+line);
        //Pattern pattern = Pattern.compile("(\\s+)(ttl=\\d+)(\\s+)", Pattern.CASE_INSENSITIVE);
        //Matcher matcher = pattern.matcher(line); // 正则表达式；寻找对应字符的数据流；
        //循环判断正则表达式中是否包含以上的规则数据；
        if(line.indexOf("time=") >= 0) {
            return 1;
        }
        return 0;
    }

}
